package main

import (
	"encoding/json"
	"fmt"
	"reflect"
)

/**
 *
 * 在 Go 中，`tag` 是结构体字段的一种元数据，通常用于为字段提供额外的信息，这些信息可以通过反射机制（reflection）读取和使用。它与 Java 中的 **注解（Annotation）** 比较相近。

以下是两者的对比分析：

---

### 1. **功能相似性**
- **Go 的 Tag**：
  - 定义在结构体字段中，形式为 `json:"field_name"` 或其他自定义格式。
  - 主要用于序列化/反序列化（如 JSON、XML）、数据库映射等场景。
  - 示例：
    ```go
    type Person struct {
        Name  string `json:"name"`
        Age   int    `json:"age"`
        Email string `json:"-"`
    }
    ```

    - `json:"name"` 表示字段 `Name` 在 JSON 序列化时对应的键名为 `name`。
    - `json:"-"` 表示字段 `Email` 不会被序列化。

- **Java 的 Annotation**：
  - 定义在类、方法或字段上，形式为 `@AnnotationName`。
  - 常用于框架配置、代码生成、运行时行为控制等。
  - 示例：
    ```java
    public class Person {
        @JsonProperty("name")
        private String name;

        @JsonIgnore
        private String email;
    }
    ```

    - `@JsonProperty("name")` 类似于 Go 的 `json:"name"`。
    - `@JsonIgnore` 类似于 Go 的 `json:"-"`。

---

### 2. **作用范围**
- **Go 的 Tag**：
  - 仅限于结构体字段，不能用于方法或全局变量。
  - 需要通过反射读取，例如使用 `reflect.StructTag`。

- **Java 的 Annotation**：
  - 可以用于类、方法、字段、参数等多种场景。
  - 支持编译期处理（通过注解处理器）和运行时处理（通过反射）。

---

### 3. **语法差异**
- **Go 的 Tag**：
  - 内联在字段声明中，形式为 `key:"value"`。
  - 示例：`Name string json:"name"`

- **Java 的 Annotation**：
  - 独立于字段声明，形式为 `@AnnotationName`。
  - 示例：`@JsonProperty("name") private String name;`

---

### 4. **应用场景**
- **Go 的 Tag**：
  - 主要用于第三方库或框架，例如：
    - JSON 序列化（`encoding/json`）。
    - 数据库 ORM 映射（如 GORM 使用的 `gorm:"column:name"`）。
    - 验证规则（如 `validate:"required"`）。

- **Java 的 Annotation**：
  - 更加广泛，例如：
    - Spring 框架中的依赖注入（`@Autowired`）。
    - JPA 中的数据库映射（`@Column`）。
    - JSON 序列化（`@JsonProperty`）。

---

### 总结
Go 的 `tag` 和 Java 的 `annotation` 在功能上有一定的相似性，都用于为代码元素附加元数据。但两者的作用范围和语法有所不同：
- Go 的 `tag` 更专注于结构体字段的元数据标注。
- Java 的 `annotation` 则是一个更通用的机制，适用于多种场景。
*/

type MyType struct {
	Name string `json:"name"`
	Address
}
type Address struct {
	City string `json:"city"`
}

type TypeA struct {
	P1 string
}

type TypeB struct {
	P2 string
	TypeA
}

func main() {
	mt := MyType{Name: "test", Address: Address{City: "shanghai"}}
	b, _ := json.Marshal(mt)
	fmt.Println(string(b))
	myType := reflect.TypeOf(mt)
	name := myType.Field(0)
	tag := name.Tag.Get("json")
	println(tag)
	tb := TypeB{P2: "p2", TypeA: TypeA{P1: "p1"}}
	// 可以直接访问TypeA.P1
	println(tb.P1)
}
